﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using MeetSomeNearbyStranger.DataModels;
using MeetSomeNearbyStrangerWebApi.Repositories;
using MeetSomeNearbyStrangerWebApi.Models;
using MeetSomeNearbyStrangerWebApi.Mappers;
using System.Web.Http.ValueProviders;
using MeetSomeNearbyStrangerWebApi.Attributes;

namespace MeetSomeNearbyStrangerWebApi.Controllers
{
    public class MeetsController : BaseController
    {
        private DbUsersRepository usersRepository;
        private DbMeetsRepository meetsRepository;
        private PubNubSender pubnub;

        public MeetsController(DbUsersRepository usersRepository, DbMeetsRepository meetsRepository, PubNubSender pubnub)
        {
            this.usersRepository = usersRepository;
            this.meetsRepository = meetsRepository;
            this.pubnub = pubnub;
        }

        [HttpPost, ActionName("arrange")]
        public HttpResponseMessage SendMeetRequest([ValueProvider(typeof(HeaderValueProviderFactory<string>))]string userID, int profileId)
        {
            HttpResponseMessage responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    User initiator = null;
                    try
                    {
                        initiator = this.usersRepository.GetByUserID(userID);
                    }
                    catch (Exception)
                    {
                        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Device is not registered in the system!");
                    }

                    User target = this.usersRepository.GetById(profileId);
                    Meet meet = new Meet()
                    {
                        Initiator = initiator,
                        Target = target,
                        Latitutde = (initiator.Latitude + target.Latitude) / 2,
                        Longitude = (initiator.Longitude + target.Longitude) / 2,
                        Accepted = false,
                    };
                    this.meetsRepository.Add(meet);

                    this.pubnub.Send("channel" + profileId, "User " + initiator.Id + " asks to meet.");

                    HttpResponseMessage response = this.Request.CreateResponse(HttpStatusCode.NoContent);
                    return response;
                });

            return responseMsg;
        }

        [HttpPut, ActionName("accept")]
        public HttpResponseMessage AcceptMeetRequest(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string userID, int meetId)
        {
            HttpResponseMessage responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    User user = null;
                    try
                    {
                        user = this.usersRepository.GetByUserID(userID);
                    }
                    catch (Exception)
                    {
                        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Device is not registered in the system!");
                    }

                    Meet meet = this.meetsRepository.Get(meetId);
                    meet.Accepted = true;
                    this.meetsRepository.Update(meetId, meet);

                    HttpResponseMessage response = this.Request.CreateResponse(HttpStatusCode.OK);
                    return response;
                });

            return responseMsg;
        }

        [HttpPut, ActionName("decline")]
        public HttpResponseMessage DeclineMeetRequest(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string userID, int meetId)
        {
            HttpResponseMessage responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    User user = null;
                    try
                    {
                        user = this.usersRepository.GetByUserID(userID);
                    }
                    catch (Exception)
                    {
                        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Device is not registered in the system!");
                    }

                    Meet meet = this.meetsRepository.Get(meetId);
                    meet.Declined = true;
                    this.meetsRepository.Update(meetId, meet);

                    HttpResponseMessage response = this.Request.CreateResponse(HttpStatusCode.OK);
                    return response;
                });

            return responseMsg;
        }

        [HttpGet, ActionName("getmy")]
        public HttpResponseMessage GetMyMeets(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string userID)
        {
            HttpResponseMessage responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    User user = null;
                    try
                    {
                        user = this.usersRepository.GetByUserID(userID);
                    }
                    catch (Exception)
                    {
                        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Device is not registered in the system!");
                    }

                    IEnumerable<Meet> meetEntities = this.meetsRepository.GetAll().Where(x => x.Initiator.UserID == userID || x.Target.UserID == userID);

                    string myNickname = user.Nickname;

                    IEnumerable<MeetModel> meets =
                        from meet in meetEntities
                        select MeatsMapper.ToMeatModel(meet, myNickname);

                    HttpResponseMessage response = this.Request.CreateResponse<IEnumerable<MeetModel>>(HttpStatusCode.OK, meets);
                    return response;
                });

            return responseMsg;
        }

        [HttpGet, ActionName("get")]
        public HttpResponseMessage GetMeet(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string userID, int meetId)
        {
            HttpResponseMessage responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    User user = null;
                    try
                    {
                        user = this.usersRepository.GetByUserID(userID);
                    }
                    catch (Exception)
                    {
                        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Device is not registered in the system!");
                    }

                    Meet meetEntity = this.meetsRepository.Get(meetId);
                    MeetModel meet = MeatsMapper.ToMeatModel(meetEntity, user.Nickname);

                    HttpResponseMessage response = this.Request.CreateResponse<MeetModel>(HttpStatusCode.OK, meet);
                    return response;
                });

            return responseMsg;
        }
    }
}
